﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Security.AccessControl;
using System.Text;

namespace Mrsoft.Common
{
    /// <summary>
    /// 流的相关拓展
    /// 网络流拓展http协议的接收
    /// </summary>
    public static class StreamExtends
    {
        /// <summary>
        /// 将字节数组完全写入流中
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="buffer"></param>
        public static void Write(this Stream stream, byte[] buffer) {
            stream.Write(buffer, 0, buffer.Length);
        }

        /// <summary>
        /// 将文本写入流中
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="message"></param>
        public static void Write(this Stream stream, string message) {
            stream.Write(Encoding.ASCII.GetBytes(message));
        }

        /// <summary>
        /// 以Format的方式来构建文本写入流
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="message">模块文本</param>
        /// <param name="extraMessage">参数信息</param>
        public static void Write(this Stream stream, string message, params  object[] extraMessage) {
            stream.Write(string.Format(message, extraMessage));
        }

        /// <summary>
        /// 从网络流中获取返回数据
        /// </summary>
        /// <param name="ns">网络流</param>
        /// <param name="ms">接收数据流如果</param>
        /// <returns></returns>
        public static Encoding GetResponse(this NetworkStream ns, Stream ms, Encoding encoding = null) {

            encoding = encoding ?? Encoding.Default;//Encoding.UTF8;
            ms = ms ?? new MemoryStream();

            ns.ReadTimeout = 10 * 1000;
            long contentLength = 0;

            #region 获取http响应头
            var f1 = '\r';
            var f2 = '\n';
            var buffer = new byte[1];
            var fi = 0;
            List<byte> bf = new List<byte>();

            bool chunked = false;

            while (true) {
                ns.Read(buffer, 0, 1);
                fi = (buffer[0] == f1 || buffer[0] == f2) ? (++fi) : 0;
                if (fi == 0) {
                    bf.Add(buffer[0]);
                }
                if (fi > 1) {
                    var str = Encoding.ASCII.GetString(bf.ToArray());
                    if (str.StartsWith("Content-Type", StringComparison.OrdinalIgnoreCase)) {
                        var index = str.IndexOf("=");
                        if (index > 0)
                            encoding = Encoding.GetEncoding(str.Substring(index + 1).Trim());
                    }
                    else if (str.StartsWith("Content-Length", StringComparison.OrdinalIgnoreCase)) {
                        var index = str.IndexOf(":");
                        if (index > 0)
                            long.TryParse(str.Substring(index + 1).Trim(), out contentLength);
                    }
                    else if (!chunked && str.StartsWith("Transfer-Encoding", StringComparison.OrdinalIgnoreCase)) {
                        var index = str.IndexOf(":");
                        if (index > 0)
                            chunked = true;
                    }
                    else if (str.StartsWith("Location", StringComparison.OrdinalIgnoreCase)) {
                        var index = str.IndexOf(":");
                        if (index > 0)
                            ms.Write(encoding.GetBytes(str.Substring(index + 1).Trim()));
                        return encoding;
                    }
                    //Console.WriteLine(str);
                    bf.Clear();
                }
                if (fi > 3) {
                    break;
                }
            }
            #endregion

            if (chunked || contentLength == 0) {
                #region 获取长度失败了就尝试直接接收
                while (true) {
                    #region Chuncked的长度
                    using (var hs = new MemoryStream(128)) {
                        while (true) {
                            ns.Read(buffer, 0, 1);
                            fi = (buffer[0] == f2 || buffer[0] == f1) ? (++fi) : 0;
                            hs.WriteByte(buffer[0]);
                            if (fi > 1) { break; }
                        }
                        string str = encoding.GetString(hs.ToArray()).Replace("\r\n", "");
                        //解析chunked的长度
                        if (!Int64.TryParse(str, System.Globalization.NumberStyles.HexNumber, null, out contentLength) && !!Int64.TryParse(str, out contentLength)) {
                            ms.Write(hs.ToArray());
                            chunked = false;
                        }
                        else {
                            if (contentLength == 0)
                                return encoding;
                            contentLength += 2;
                        }
                    }
                    #endregion
                    try {
                        if (chunked) {
                            buffer = new byte[(contentLength > 20480) ? 20480 : contentLength];
                            while (contentLength > 0) {
                                if (contentLength < buffer.Length)
                                    buffer = new byte[contentLength];
                                var recv = ns.Read(buffer, 0, buffer.Length);
                                ms.Write(buffer, 0, recv);
                                contentLength -= recv;
                            }
                        }
                        else {
                            buffer = new byte[20480];
                            while (true) {
                                var recv = ns.Read(buffer, 0, buffer.Length);
                                if (recv == 0)
                                    return encoding;
                                ms.Write(buffer, 0, recv);
                            }
                        }
                    }
                    catch { return encoding; }
                }

                #endregion
            }

            #region 接收数据
            buffer = new byte[(contentLength > 20480) ? 20480 : contentLength];
            while (contentLength > 0) {
                var recv = ns.Read(buffer, 0, buffer.Length);
                ms.Write(buffer, 0, recv);
                contentLength -= recv;
            }
            #endregion

            return encoding;
        }
    }
}
